/* eslint-disable @typescript-eslint/no-explicit-any */
// by little sound @ 2023, tg vue magic
// 开始：注入功能实现
function createContext() {
  const ctx = new WeakMap();

  function put<T>(dep: (...p: any[]) => T, p: T) {
    ctx.set(dep, p);
  }

  function find<T>(dep: (p: T) => T): T {
    return ctx.get(dep);
  }

  return { put, find };
}

type Content = ReturnType<typeof createContext> & {};

type UseDependency<T> = {
  (ctx: Content): T;
  provide(ctx: Content, p: T): UseDependency<T>;
};

function defineDependency<T>(name = "Unknown") {
  const useDependency: UseDependency<T> = (ctx: Content) => {
    const dependency = ctx.find(useDependency as any) as any;
    if (dependency === undefined) {
      throw new Error(`Dependency not found: ${name}`);
    }
    return dependency;
  };
  const provide = (ctx: Content, p: T) => {
    ctx.put(useDependency, p);
    return useDependency;
  };

  useDependency.provide = provide;
  return useDependency;
}
// 结束：注入功能实现

// 开始：使用示例

// Config Dependency
interface Config {
  app: string;
  host: string;
  port: number;
}

const useConfig = defineDependency<Config>("Config");

function config(ctx: Content) {
  useConfig.provide(ctx, {
    app: "Ayaka Cat Nest",
    host: "ayaka.moe",
    port: 443,
  });
}

// Http Dependency
interface HttpClient {
  get: () => any;
  post: () => any;
}

const useHttpClient = defineDependency<HttpClient>("HttpClient");

function httpClient(ctx: Content) {
  const { host, port } = useConfig(ctx);
  const url = `${host}:${port}`;
  useHttpClient.provide(ctx, {
    get: () => console.log("get:", url),
    post: () => console.log("post:", url),
  });
}

// Controllers
function controller(ctx: Content) {
  const config = useConfig(ctx);
  const httpClient = useHttpClient(ctx);

  console.log("App Name", config.app);
  httpClient.get();
  httpClient.post();
}

// Program Entry
function main() {
  const ctx = createContext();
  config(ctx);
  httpClient(ctx);
  controller(ctx);
}

if (import.meta.main) {
  main();
}
